#include "../echo_service.pb.h"
#include "../RpcChannel.h"
#include "../../TcpConnection.h"
#include "../../TcpClient.h"
#include "../../EventLoop.h"
#include <memory>
#include "../RpcController.h"
#include "../../Channel.h"

using namespace std::placeholders;

class RpcClient
{
public:
    RpcClient(EventLoop* loop, const string& ip, const int port)
        : loop_(loop)
        , client_(loop, ip, port)
        , channel_(new RpcChannel)
        , stub_(channel_.get())
        , stdinChannel_(loop, 0)
    {
        client_.setConnectionCallback(std::bind(&RpcClient::onConnection, this, _1));
        client_.setMessageCallback(std::bind(&RpcChannel::onMessage, channel_.get(), _1, _2));
        // client_.enableRetry();
        stdinChannel_.setReadCallback(std::bind(&RpcClient::handleRead, this));
        stdinChannel_.enableReading();
    }

    void connect()
    {
        client_.connect();
    }

private:
    void onConnection(const TcpConnectionPtr& conn) 
    {
        // conn->connected();
        std::cout << "RpcClient onConnection" << std::endl;
        // if (conn->connected())
        // {
        //     channel_->setConnection(conn);

        //     EchoRequest request;
        //     request.set_message("Hello World!");
        //     EchoResponse* response = new EchoResponse;

        //     RpcController cntl;
        //     auto donClosure = google::protobuf::NewCallback(this, &RpcClient::doneCallback, response);
        //     stub_.Echo(&cntl, &request, response, donClosure);
        // }
        // else 
        // {
        //     loop_->quit();
        // }
        
        std::cout << "Send your message : " << std::endl;
    }

    void doneCallback(EchoResponse* response)
    {
        // std::cout << "EchoResponse doneCallback" << std::endl;
        std::cout << response->DebugString() << std::endl;
        // client_.disconnect();
    }

    void handleRead()
    {
        char buf[1024] = {0};
        fgets(buf, 1024, stdin);
        buf[strlen(buf)-1] = '\0';
        std::string msg(buf);
        // std::cout << "string : " << msg << std::endl;
        channel_->setConnection(client_.connection());

        EchoRequest request;
        // request.set_message("Hello World!");
        request.set_message(msg);
        EchoResponse* response = new EchoResponse;

        RpcController cntl;
        auto donClosure = google::protobuf::NewCallback(this, &RpcClient::doneCallback, response);
        stub_.Echo(&cntl, &request, response, donClosure);
    }

    EventLoop* loop_;
    TcpClient client_;
    RpcChannelPtr channel_;
    EchoServer_Stub stub_;

    Channel stdinChannel_;
};

int main(int argc, char* argv[]) {

    // if (argc < 2)
    // {
    //     fprintf(stderr, "Usage: %s listen_port backend_ip:port [backend_ip:port]\n", argv[0]);
    //     exit(0);
    // }
    // int port = atoi(argv[1]);
    // std::cout << "listen port : " << port << std::endl;

    EventLoop loop;
    std::string ip = "127.0.0.1";
    int port = 12345;

    RpcClient rpcClient(&loop, ip, port);
    rpcClient.connect();
    loop.loop();

    return 0;
}


// g++ -std=c++17 client.cpp ../*.cpp ../../*.cpp -lpthread -lprotobuf -o client
